/************************************************************************
 * Este archivo, representa metodos y variables relacionadas con la 
 * funcionalidad de chequeo de estado de clientes de la cochera
 * 
 * @system: veco-system
 * @description: Sistema de control vehicular
 * @version: 1.0
 * @Copyright © 2013 
 * 
 * @authores:
 * 
 *      > Alberione, Fernando    <falberione_037@gmail.com>
 * 
 *      > Boretto, Martin        <martinboretto@gmail.com>
 * 
 *      > Lenarduzzi, Federico   <fedeatenas@gmail.com>
 * 
 *      > Ocampo, Emanuel        <eocampo86@gmail.com>
 *
 *************************************************************************/

package SistemaCocheras;

import java.io.IOException;
import java.sql.Connection;
import java.sql.Date;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Calendar;
import java.util.GregorianCalendar;


public class manejadorEstadoCliente {
    
    private Connection conexion = null;
    
    
    // ---------------------------------------------------------
    // ------- Seccion de constructores de la clase
    // ---------------------------------------------------------      

    /**
     * Constructor NO vacio
     */    
    public manejadorEstadoCliente(Connection c){
        this.conexion = c;
    }
    

    // ---------------------------------------------------------
    // ------- Seccion de metodos publicos
    // ---------------------------------------------------------
    
    /**
     * Metodo encargado de generar el pago de un cliente, imprimir su ticket e
     * ingresar el mismo en la base de datos
     * @param dni Representa el dni del cliente
     * @param dniUsuario Representa el dni del usuario que realiza el cobro
     * @return montoFinal Representa el monto total a abonar
     * @throws SQLException
     * @throws IOException 
     */
    public double marcarPago (String dni, String dniUsuario) throws SQLException, IOException{
        manejadorCliente mcl = new manejadorCliente(this.conexion);
        manejadorCochera mco = new manejadorCochera(this.conexion);
        manejadorEstadia me  = new manejadorEstadia(this.conexion);
        manejadorVehiculo mv = new manejadorVehiculo(this.conexion);
        ResultSet datosCliente = null;
        double montoFinal = 0.0;
        datosCliente = mcl.buscarClientePorDni(dni);
        if(datosCliente.next()){
            int numTarifa = datosCliente.getInt("tipotarifa");
            double dto = datosCliente.getInt("porcentaje_descuento");
            Double [] tarifasAuto = mco.obtenerMontoTarifa(0);
            Double [] tarifasCamioneta = mco.obtenerMontoTarifa(1);
            Double [] tarifasMoto = mco.obtenerMontoTarifa(2);
            ResultSet vehiculosClientes = mv.buscarVehiculosPorCliente(dni);
            double monto = calcularMontoVehiculos(vehiculosClientes, numTarifa, tarifasAuto, tarifasCamioneta, tarifasMoto);
            // Si tiene descuento, se aplica al total
            montoFinal = monto - ((monto * dto)/ 100);               
            int diasPeriodo = 0;
            switch (numTarifa){
                case (0): 
                    // Periodo semanal
                    diasPeriodo = 7;          
                    break;
                case (1): 
                    // Periodo quincenal
                    diasPeriodo = 15;         
                    break;
                case (2): 
                    // Periodo mensual
                    diasPeriodo = 30;         
                    break;
            }
            ResultSet ultimoPeriodo = obtenerUltimoPeriodo(dni);
            String fechaActual = me.calcularFecha();
            String [] parsing = fechaActual.split("-");
            Calendar fechaCorriente = new GregorianCalendar(Integer.parseInt(parsing[0]),
                                                            Integer.parseInt(parsing[1])-1,
                                                            Integer.parseInt(parsing[2]));
            Calendar fechaAux = fechaCorriente;
            if (!ultimoPeriodo.next()){
                // Se cobra la primer cuota
                cobrarPrimerCuota(fechaCorriente, fechaAux, diasPeriodo, dni, montoFinal);
            }
            else {
                // Se cobra la proxima cuota
                cobrarProximaCuota(fechaCorriente, fechaAux, ultimoPeriodo, diasPeriodo, dni, montoFinal);
            }
            manejadorCaja mc = new manejadorCaja(this.conexion);
            mc.insertarIngreso("Pago de Cliente", dniUsuario, montoFinal, me.calcularFecha(), me.calcularHora());
        }
        return montoFinal;
    }// Fin marcarPago

    
    
    // ---------------------------------------------------------
    // ------- Seccion de metodos privados
    // ---------------------------------------------------------
    
    /**
     * Metodo encargado de realizar el pago de la primer cuota del cliente
     * @param fechaCorriente Representa la fecha corriente del pago
     * @param fechaAux Representa una fecha auxiliar para calcular el rango
     * @param diasPeriodo Representa los dias del periodo de pago
     * @param dni Representa el dni del cliente
     * @param montoFinal Representa el monto total a pagar
     * @throws SQLException
     * @throws IOException 
     */
    private void cobrarPrimerCuota(Calendar fechaCorriente, Calendar fechaAux, int diasPeriodo, 
                                   String dni, double montoFinal) throws SQLException, IOException{
        fechaAux = new GregorianCalendar(fechaCorriente.get(Calendar.YEAR),
                                        fechaCorriente.get(Calendar.MONTH),
                                        fechaCorriente.get(Calendar.DAY_OF_MONTH));
        fechaCorriente.add(Calendar.DAY_OF_MONTH, diasPeriodo);
        Date fechaInicio = parseDate(fechaAux);
        Date fechaFin = parseDate(fechaCorriente);
        insertarEstadoCliente(dni, fechaInicio, fechaFin, montoFinal);
        Tickets ticket = new Tickets(this.conexion);
        Date fechaAct = parseDate(fechaAux);
        ticket.imprimirTicketPago(dni, fechaAct, fechaInicio, fechaFin, montoFinal);
    }// Fin cobrarPrimerCuota
    
    
    /**
     * Metodo encargado de realizar el pago de la proxima cuota del cliente
     * @param fechaCorriente Representa la fecha corriente del pago
     * @param fechaAux Representa una fecha auxiliar para calcular el rango
     * @param ultimoPeriodo Representa el ultimo periodo de pago del cliente
     * @param diasPeriodo Representa los dias del periodo de pago
     * @param dni Representa el dni del cliente
     * @param montoFinal Representa el monto total del pago
     * @throws SQLException
     * @throws IOException 
     */
    private void cobrarProximaCuota(Calendar fechaCorriente, Calendar fechaAux, ResultSet ultimoPeriodo, 
                                    int diasPeriodo, String dni, double montoFinal) throws SQLException, IOException{
        int anio = ultimoPeriodo.getDate(3).getYear()+1900;
        int mes = ultimoPeriodo.getDate(3).getMonth();
        int dia = Integer.parseInt(((ultimoPeriodo.getDate(3).toString()).split("-"))[2]);
        Calendar fechaUltimoPeriodo = new GregorianCalendar(anio, mes, dia);
        if (esClienteMoroso(fechaCorriente, fechaUltimoPeriodo)){
            // Es un cliente moroso
            fechaAux = new GregorianCalendar(fechaCorriente.get(Calendar.YEAR),
                                             fechaCorriente.get(Calendar.MONTH),
                                             fechaCorriente.get(Calendar.DAY_OF_MONTH));
            fechaCorriente.add(Calendar.DAY_OF_MONTH,diasPeriodo);
            Date fechaInicio = parseDate(fechaAux);
            Date fechaFin = parseDate(fechaCorriente);
            insertarEstadoCliente(dni, fechaInicio, fechaFin, montoFinal);
            Tickets ticket = new Tickets(this.conexion);
            Date fechaAct = parseDate(fechaAux);
            ticket.imprimirTicketPago(dni, fechaAct, fechaInicio, fechaFin, montoFinal);
        }
        else{
            // Es un cliente que pago a termino
            fechaAux = new GregorianCalendar(fechaUltimoPeriodo.get(Calendar.YEAR),
                                             fechaUltimoPeriodo.get(Calendar.MONTH),
                                             fechaUltimoPeriodo.get(Calendar.DAY_OF_MONTH));
            fechaUltimoPeriodo.add(Calendar.DAY_OF_MONTH,diasPeriodo);
            Date fechaInicio = parseDate(fechaAux);
            Date fechaFin = parseDate(fechaUltimoPeriodo);
            insertarEstadoCliente(dni, fechaInicio, fechaFin, montoFinal);
            Tickets ticket = new Tickets(this.conexion);
            Date fechaAct = parseDate(fechaCorriente);
            ticket.imprimirTicketPago(dni, fechaAct, fechaInicio, fechaFin, montoFinal);
        }        
    }// Fin cobrarProximaCuota
    
    
    /**
     * Metodo encargado de controlar si un cliente esta fuera de termino o no
     * @param fCorriente Representa la fecha corriente
     * @param fUltimoPeriodo Representa la fecha del ultimo periodo de pago
     * @return true o false 
     */
    private boolean esClienteMoroso(Calendar fCorriente, Calendar fUltimoPeriodo){
        return (fCorriente.after(fUltimoPeriodo));
    }// Fin esClienteMoroso

    
    /**
     * Metodo encargado de calcular el monto correspondiente a los vehiculos
     * de un cliente en particular
     * @param vehiculosC Representa el/los vehiculos del cliente
     * @param numTarifa Representa el numero de tarifa a abonar
     * @param tarifasAuto Representa las tarifas de automoviles
     * @param tarifasCamioneta Representa las tarifas de camionetas
     * @param tarifasMoto Representa las tarifas de motocicletas
     * @return monto
     * @throws SQLException 
     */
    private double calcularMontoVehiculos(ResultSet vehiculosC, int numTarifa, Double [] tarifasAuto, 
                                         Double [] tarifasCamioneta, Double [] tarifasMoto) throws SQLException{
        double monto = 0.0;
        while (vehiculosC.next()){
            switch (vehiculosC.getInt("tipo")){
                case (0):{
                    monto += tarifasAuto[numTarifa+4];
                    break;
                }
                case (1):{
                    monto += tarifasCamioneta[numTarifa+4];
                    break;
                }
                case (2):{
                    monto += tarifasMoto[numTarifa+4];
                    break;
                }
            }
        }
        return monto;
    }// Fin calcularMontoVehiculos
    
    
    /**
     * Metodo encargado de insertar el estado de un cliente en la base de datos
     * @param dni Representa el dni del cliente a insertar
     * @param fechaI Representa la fecha de ingreso del cliente
     * @param fechaF Representa la fecha de egreso del cliente
     * @param monto Representa el monto a pagar del cliente
     * @throws SQLException 
     */
    private void insertarEstadoCliente (String dni, Date fechaI, Date fechaF, Double monto) throws SQLException{
        Statement statemen = this.conexion.createStatement();
        String consulta = "INSERT INTO estadocliente VALUES ('"+dni+"','"+fechaI+"','"+fechaF+"','"+monto+"');";
        statemen.executeUpdate(consulta);
    }// Fin insertarEstadoCliente


    /**
     * Metodo encargado de retornar el ultimo periodo de pago del cliente
     * @param dni Representa el dni del cliente
     * @return res
     * @throws SQLException 
     */
    private ResultSet obtenerUltimoPeriodo (String dni) throws SQLException{
        ResultSet res = null;
        Statement statemen = this.conexion.createStatement();
        String consulta = "SELECT * FROM estadocliente WHERE dniC='"+dni+"' and fechafin IN (SELECT MAX(fechafin) as fechafin FROM estadocliente WHERE dniC='"+dni+"')";
        res = statemen.executeQuery(consulta);
        return res;
    }// Fin obtenerUltimoPeriodo

    
    /**
     * Metodo encargado de convertir un calendar a un date
     * @param c Representa el calendar a convertir
     * @return date
     */
    private Date  parseDate(Calendar c){
        int anio = c.get(Calendar.YEAR)-1900;
        int mes  = c.get(Calendar.MONTH);
        int dia  = c.get(Calendar.DAY_OF_MONTH);
        return (new Date(anio, mes, dia));
    }// Fin parseDate


}// Fin clase manejadorEstadoCliente
